package sma.agents;

import ihm.AppliWindow;

import java.util.Collections;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JLayeredPane;

import org.janusproject.kernel.address.Address;
import org.janusproject.kernel.channels.Channel;
import org.janusproject.kernel.channels.ChannelInteractable;
import org.janusproject.kernel.crio.core.GroupAddress;
import org.janusproject.kernel.status.Status;
import org.janusproject.kernel.status.StatusFactory;

import sma.agents.bodies.GoalAgentBody;
import sma.agents.channels.GoalChannel;
import sma.agents.listeners.MoveGoalListener;
import sma.agents.listeners.MoveListener;
import sma.environment.LocalEnvironment;
import sma.organizations.VirtualEnvironmentOrga;
import sma.organizations.roles.Goal;
import sma.organizations.signals.SendMoveGoalSignal;
import appli.utils.Config;
import appli.utils.MoveEnum;

/**
 * GoalAgent est l'agent qui fixe l'objectif de la voiture. Eventuellement on
 * peut en lancer plusieurs pour plusieurs objectifs.
 * Depuis la 0.2 l'agent utilise les channels pour communiquer avec la GUI
 * 
 * @author Etienne Sainton
 * @version 0.2
 */
public class GoalAgent extends StandartAgent implements ChannelInteractable, MoveGoalListener {
	private final GoalChannelImpl channelImpl = new GoalChannelImpl();
	
	/**
	 * Constructeur. L'agent evolue maintenant dans un environnement.
	 * 
	 * @param _environment : environnement local
	 * @param _groupe le groupe de l'agent
	 * @see LocalEnvironment
	 */
	public GoalAgent(sma.environment.LocalEnvironment _environment, int _groupe) {
		// On définit l'environnement :
		this.environment = _environment;

		//Le gorupe de l'agent :
		this.groupe = _groupe;
		
		// On vérifie l'implementation de la memoire
		memory = getMemory();
		assert (memory != null);

		// On lui affecte un body propre à son role :
		this.body = new GoalAgentBody();

		// Et on confirme
		if (Config.DEBUG == true)
			System.out.println("Agent Goal operationnel");
		
		channelImpl.addMoveGoalListener(this);
	}

	/**
	 * activate, Permet d'activer l'agent avant qu'il vive. Il prend pour role
	 * Goal. Par ailleurs des paramtres de sortie s'afficheront en cas de mode
	 * debug.
	 * 
	 * @param parameters inutile de mettre quelque chose ici
	 */
	@Override
	public Status activate(Object... parameters) {
		super.init((JComponent) parameters[0]);
		
		//if (Config.DEBUG == true)
			System.out.println("Agent Goal activé");

		// Recuperation de l'adresse du groupe Voiture
		GroupAddress virtuelEnvGA = getOrCreateGroup(VirtualEnvironmentOrga.class);

		// Affectation du role de Goal dans le groupe Voiture
		if (requestRole(Goal.class, virtuelEnvGA, this.environment, this.body, this.groupe)) {
			if (Config.DEBUG == true)
				System.out.println("Agent Goal appartient au role Goal dans le groupe VirtualEnvironment");
			return StatusFactory.ok(this);
		} else if (Config.DEBUG == true)
			System.out.println("L'agent Goal ne peut pas appartenir au role Goal dans le groupe VirtualEnvironment...");

		return StatusFactory.cancel(this);
	}

	/**
	 * Mort de l'agent
	 */
	@Override
	public Status end() {
		if (Config.DEBUG == true)
			print("Je suis mort....");
		return StatusFactory.ok(this);
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public <C extends Channel> C getChannel(Class<C> channelClass, Object... params) {
		if (channelClass.isAssignableFrom(GoalChannel.class)) {
			return channelClass.cast(this.channelImpl);
		}
		return null;
	}


	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set<? extends Class<? extends Channel>> getSupportedChannels() {
		return Collections.singleton(GoalChannel.class);
	}


	private class GoalChannelImpl implements GoalChannel {
		@Override
		public Address getChannelOwner() {
			return getAddress();
		}

		@Override
		public void addMoveGoalListener(MoveGoalListener listener) {
			GoalAgent.this.addEventListener(MoveGoalListener.class, listener);
		}

		@Override
		public void removeMoveGoalListener(MoveGoalListener listener) {
			GoalAgent.this.removeEventListener(MoveGoalListener.class, listener);
		}

		@Override
		public void moveGoal(int _groupe, MoveEnum move) {
			//if(_groupe == StandartAgent.groupe) {
				System.out.println("fire");
				fireSignal(new SendMoveGoalSignal(this, move, _groupe));
			//}
			//else
			//	System.out.println("pas mon groupe");
		}
	}


	@Override
	public void onMoveGoal(MoveEnum move) {
		MoveListener[] list = getEventListeners(MoveListener.class);

        for (MoveListener listener : list) {
                listener.onMoveAgent(getAddress(), getBody(), groupe);
        }
	}

	/**
	 * @return the channelImpl
	 */
	public GoalChannelImpl getChannelImpl() {
		return channelImpl;
	}
}
